﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Newtonsoft.Json;

namespace RegulatoryPlatform.Tools
{
    /// <summary>
    /// 获取研发数据
    /// </summary>
    public class RDData
    {
        /// <summary>
        /// 研发接口地址
        /// </summary>
        public string BaseUrl { get; set; }
        public string AppId { get; set; }
        /// <summary>
        /// 公钥
        /// </summary>
        public string PublicKey { get; set; }
        /// <summary>
        /// 私钥
        /// </summary>
        public string PrivateKey { get; set; }

        public RDData(string appId, string publicKey, string privateKey)
        {
            BaseUrl = ConfigurationManager.AppSettings["BaseUrl"].ToString();
            AppId = appId;
            PublicKey = publicKey;
            PrivateKey = privateKey;
        }
        #region Http post
        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受   
        }
        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="address"></param>
        /// <param name="body"></param>
        /// <param name="contentType"></param>
        /// <returns></returns>
        public string PostHttp(string address, string body, string contentType)
        {
            DateTime time = DateTime.Now;
            string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");
            string filePath = logPath + "\\" + time.ToString("yyyy-MM-dd") + ".txt";
            if (!File.Exists(filePath))
            {
                File.Create(filePath);
            }
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            string url = BaseUrl + address;
            FileHelper.AppendSave("url:" + url + "\n", filePath);
            FileHelper.AppendSave("body:" + body + "\n", filePath);
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);

            httpWebRequest.ContentType = contentType;

            httpWebRequest.Method = "POST";
            httpWebRequest.Timeout = 60000;

            byte[] btBodys = Encoding.UTF8.GetBytes(body);
            httpWebRequest.ContentLength = btBodys.Length;
            httpWebRequest.GetRequestStream().Write(btBodys, 0, btBodys.Length);

            HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
            string responseContent = streamReader.ReadToEnd();

            httpWebResponse.Close();
            streamReader.Close();
            httpWebRequest.Abort();
            httpWebResponse.Close();
            FileHelper.AppendSave("responseContent:" + responseContent + "\n", filePath);
            return responseContent;
        }

        #endregion

        #region SHA1 with RSA签名
        /// <summary>
        /// SHA1withRSA签名
        /// </summary>
        /// <param name="content">待签名字符串</param>
        /// <param name="privateKey">私钥</param>
        /// <param name="input_charset">编码格式</param>
        /// <returns>签名后字符串</returns>
        public string Sign(string content, string privateKey, string input_charset)
        {
            byte[] Data = Encoding.GetEncoding(input_charset).GetBytes(content);
            RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
            using (var sh = SHA1.Create())
            {
                byte[] signData = rsa.SignData(Data, sh);
                return Convert.ToBase64String(signData);
            }
        }
        private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)
        {
            RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(Convert.FromBase64String(pemstr));
            return rsa;
        }
        private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
        {
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

            // --------- Set up stream to decode the asn.1 encoded RSA private key ------
            MemoryStream mem = new MemoryStream(privkey);
            BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
            byte bt = 0;
            ushort twobytes = 0;
            int elems = 0;
            try
            {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte(); //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16(); //advance 2 bytes
                else
                    return null;

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102) //version number
                    return null;
                bt = binr.ReadByte();
                if (bt != 0x00)
                    return null;


                //------ all private key components are Integer sequences ----
                elems = GetIntegerSize(binr);
                MODULUS = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                E = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                D = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                P = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                Q = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DP = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DQ = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                IQ = binr.ReadBytes(elems);

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                CspParameters CspParameters = new CspParameters();
                CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
                RSAParameters RSAparams = new RSAParameters();
                RSAparams.Modulus = MODULUS;
                RSAparams.Exponent = E;
                RSAparams.D = D;
                RSAparams.P = P;
                RSAparams.Q = Q;
                RSAparams.DP = DP;
                RSAparams.DQ = DQ;
                RSAparams.InverseQ = IQ;
                RSA.ImportParameters(RSAparams);
                return RSA;
            }
            catch
            {
                return null;
            }
            finally
            {
                binr.Dispose();
            }
        }

        private static int GetIntegerSize(BinaryReader binr)
        {
            byte bt = 0;
            byte lowbyte = 0x00;
            byte highbyte = 0x00;
            int count = 0;
            bt = binr.ReadByte();
            if (bt != 0x02) //expect integer
                return 0;
            bt = binr.ReadByte();

            if (bt == 0x81)
                count = binr.ReadByte();    // data size in next byte
            else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte(); // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt; // we already have the data size
            }

            while (binr.ReadByte() == 0x00)
            {   //remove high order zeros in data
                count -= 1;
            }
            binr.BaseStream.Seek(-1, SeekOrigin.Current);   //last ReadByte wasn't a removed zero, so back up a byte
            return count;
        }
        #endregion

        #region 调用接口

        /// <summary>
        /// 根据方法名 调用研发的接口 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public string GetDataByMethod<T>(string method, T content) where T : class, new()
        {
            string address = ConfigurationManager.AppSettings[method];
            string WaitingForsignStr = "appid=" + AppId + "&content=" + JsonConvert.SerializeObject(content);
            string sign = Sign(WaitingForsignStr, PrivateKey, "UTF-8");
            Request<T> request = new Request<T>
            {
                appid = AppId,
                sign = sign,
                content = content
            };
            string body = JsonConvert.SerializeObject(request);
            string response = PostHttp(address, body, "application/json");
            return response;
        }

        #endregion
    }

    public class Request<T> where T : class, new()
    {
        public string appid { get; set; }
        public string sign { get; set; }
        public T content { get; set; }
    }

    /// <summary>
    /// 复诊
    /// </summary>
    public class SearchrevisitResponse
    {
        /// <summary>
        /// 
        /// </summary>
        public string b_id { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string submit_time { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string receipt_time { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string patient_name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string doctor_name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string result { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string evaluate { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string status { get; set; }

    }

    /// <summary>
    /// 汇总
    /// </summary>
    public class DatastatisticsResponse
    {
        public string drfwl { get; set; }
        public string drzxl { get; set; }
        public string drwzlyb { get; set; }
        public string drwzlfyb { get; set; }
        public string drzxzlfyb { get; set; }
        public string drzxzlffyb { get; set; }
        public string drzxcfl { get; set; }
        public string drzxyjfcfl { get; set; }
    }

    /// <summary>
    /// 数据集
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Response<T> where T : class, new()
    {
        public string total { get; set; }
        public string status { get; set; }
        public string msg { get; set; }
        public List<T> content { get; set; }
    }

    /// <summary>
    /// 单条数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ResponseSingle<T> where T : class, new()
    {
        public string total { get; set; }
        public string status { get; set; }
        public string msg { get; set; }
        public T content { get; set; }
    }

    public class Response
    {
        public string total { get; set; }
        public string sign { get; set; }
        public string status { get; set; }
        public string msg { get; set; }
        public string content { get; set; }
    }
}